﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : Role
{
	public float moveSpeed;
	public GameObject bltPrefab;
	public int initHP, initMP;      // 初始血量值
	public override int Hp => initHP;
	public override int Mp => initMP;   // 本游戏中Mp表示子弹数量

	public List<Sprite> shootDirs = new List<Sprite>();
	PlayerState state;

	private ShootDirection dir;
	public ShootDirection Dir => dir;


	#region 动画限制相关属性
	private Dictionary<PlayerState, bool> isCompleted = new Dictionary<PlayerState, bool>();
	// private Queue<PKTStruct> inKeys = new Queue<PKTStruct>();

	public bool Direction => transform.localScale.x > 0;    // 当前角色方向属性

	// 能移动动画: 不贴墙, 不猛冲, 不Idle, 不Shoot, 不Water, 不暂停
	public bool AllowMove {
		get {
			return !ani.GetBool("IsWallClinging") && ani.GetInteger("MoveState") != 3 &&
				ani.GetInteger("MoveState") != 0 && !ani.GetBool("IsWater") &&
				!GameController.Instance.IsPause;
		}
	}

	// 允许攀爬: 不跳跃, 不蹲下, 不攻击
	public bool AllowClimb {
		get {
			return !isCompleted[PlayerState.Jump] && !ani.GetBool("IsCrouch") &&
				!isCompleted[PlayerState.Melee] && !isCompleted[PlayerState.Shoot];
		}
	}

	// 允许跳跃: IsJump = false, 不攀爬, 不贴墙, 不蹲下, 不Water, 不暂停
	public bool AllowJump {
		get {
			return !isCompleted[PlayerState.Jump] && !ani.GetBool("IsClimb") &&
				!ani.GetBool("IsWallClinging") && !ani.GetBool("IsCrouch") &&
				!ani.GetBool("IsWater") && !GameController.Instance.IsPause;
		}
	}

	// 允许蹲下: 不攀爬, 不跳跃, 不攻击, 不Water, 不暂停
	public bool AllowCrouch {
		get {
			return !ani.GetBool("IsClimb") && !isCompleted[PlayerState.Jump] &&
				!isCompleted[PlayerState.Melee] && !isCompleted[PlayerState.Shoot] &&
				!ani.GetBool("IsWater") && !GameController.Instance.IsPause;
		}
	}

	// 允许猛冲: MoveState != 3, 等待结束
	public bool AllowDash {
		get {
			return ani.GetInteger("MoveState") != 3 && !waitDash;
		}
	}

	#endregion



	#region 生命周期函数




	protected override void Start() {
		base.Start();
		SetIniAttributes();
		SetPlayerState(PlayerState.Idle, true);

	}

	private void Update() {
		OnUpdateGetShootDirection();    // 获取射击方向

		float x = Input.GetAxis("Horizontal");
		// Debug.Log("AllowMove:" + AllowMove);
		if (AllowMove) transform.Translate(Vector3.right * x * Time.deltaTime * moveSpeed * cntADClick);
		if (x != 0) ChangeMirrorPlayer(x > 0);  // 设置方向

		// 非循环动画
		if (Input.GetKeyDown(KeyCode.Space)) {    // 跳跃
			if (AllowJump) SetPlayerState(PlayerState.Jump);
		} else if (Input.GetKeyDown(KeyCode.J)) {   // 近距离攻击
			if (!isCompleted[PlayerState.Melee]) SetPlayerState(PlayerState.Melee);
		} else if (Input.GetKeyDown(KeyCode.K)) {   // 远距离攻击
			if (!isCompleted[PlayerState.Shoot] && CurrentMp > 0) SetPlayerState(PlayerState.Shoot);
		}

		OnUpdateSetCrouch();    // 设置蹲下状态
		OnUpdateMoveState();    // 左右移动方法
	}
	#endregion


	#region 重写重写暂停与继续
	public override void OnPauseAni() {
		base.OnPauseAni();
		rig.gravityScale = 0;

		// transform.GetChild(0).GetComponent<Collider2D>().enabled = false;
	}

	public override void OnContinueAni() {
		base.OnContinueAni();
		rig.gravityScale = 1;

		// transform.GetChild(0).GetComponent<Collider2D>().enabled = true;
	}

	#endregion


	/// <summary>
	/// 设置Player初始属性
	/// </summary>
	private void SetIniAttributes() {
		CurrentHp = Hp; CurrentMp = Mp;
		UIController.Instance.SetInitHPAndMP(this);
		this.attack = 1;
		this.roleType = RoleType.Player;
		dir = ShootDirection.Right;
		foreach (var item in Enum.GetNames(typeof(PlayerState))) {
			isCompleted.Add((PlayerState)Enum.Parse(typeof(PlayerState), item), false);
		}
	}


	#region CollisionOrTrigger触发事件

	private void OnCollisionStay2D(Collision2D other) {
		if (other.gameObject.tag == "Wall") {
			cntADClick = 3;
		}
	}
	

	private IEnumerator IRecvAttack() {
		// Color color = GetComponent<SpriteRenderer>().color;
		int loop = 30;
		float f = 1.0f / loop;
		while (loop > 0) {

			GetComponent<SpriteRenderer>().color -= new Color(0, 0, 0, Time.deltaTime * f * 100);
			loop--;
			yield return null;
		}
		loop = 30;
		while (loop > 0) {

			GetComponent<SpriteRenderer>().color += new Color(0, 0, 0, Time.deltaTime * f * 100);
			loop--;
			yield return null;
		}
		GetComponent<SpriteRenderer>().color += new Color(0, 0, 0, 1);
	}

	public void RecvAttack(int hurt) {
		if (GameController.Instance.IsGod) return;      // 上帝模式没有受伤状态
		SetPlayerState(PlayerState.Attack);
		CurrentHp = Mathf.Max(0, CurrentHp - hurt);
		UIController.Instance.SetHPAndMP(this);
		if (CurrentHp <= 0) {
			Debug.Log("主角死亡");
			GameController.Instance.EndGame(this);
		}
	}
	#endregion


	#region Player攀爬

	/// <summary>
	/// Player攀爬
	/// </summary>
	/// <param name="ladder"></param>
	public void OnClimbLadder(Ladder ladder, out bool isUp) {
		float y = Input.GetAxis("Vertical");
		isUp = y >= 0;
		if (y == 0 || !AllowClimb) return;
		SetPlayerState(PlayerState.Crouch, false);  // 攀爬前解除蹲下动画(如果有)
		SetPlayerState(PlayerState.Climb, true);
		rig.gravityScale = 0;   // 攀爬过程设定为没有重力的匀速运动
		y = y > 0 ? 1 : -1;
		transform.Translate(Vector3.up * Time.deltaTime * y * 4);
	}

	#endregion


	#region Palyer在水中的运动
	/// <summary>
	/// 进入水中
	/// </summary>
	public void OnEnterSwimming() {
		SetPlayerState(PlayerState.Water, true);
		rig.gravityScale = 0;
		StartCoroutine(ISwimming());
	}

	/// <summary>
	/// 在水中游泳
	/// </summary>
	private IEnumerator ISwimming() {


		while (ani.GetBool("IsWater")) {
			float x = Input.GetAxis("Horizontal");
			float y = Input.GetAxis("Vertical");
			Vector3 offset = new Vector3(x, y, 0);

			transform.position += offset * Time.deltaTime * 2;

			yield return null;
		}
	}

	/// <summary>
	/// 退出水中
	/// </summary>
	public void OnExitSwimming() {
		SetPlayerState(PlayerState.Water, false);
		// StopCoroutine(ISwimming());
		rig.gravityScale = 1;
	}
	#endregion



	/// <summary>
	/// 拾取Item
	/// </summary>
	/// <param name="item"></param>
	public void GetItem(Item item) {
		switch (item.itemType) {
			case ItemType.Coin:
				GameController.Instance.CntCoin++;
				break;

			case ItemType.Stimpack:
				CurrentHp = Hp;
				UIController.Instance.SetHPAndMP(this);
				break;

			case ItemType.TimeSlower:
				CurrentMp = Mathf.Min(Mp, CurrentMp + 5);
				UIController.Instance.SetHPAndMP(this);
				break;

			default:
				break;
		}
	}


	/// <summary>
	/// 掉入深渊直接死亡
	/// </summary>
	public void OnDieToAbyss(Abyss abyss) {
		Debug.Log("掉下来了直接死亡");
		RecvAttack(Hp);     // 受到全额伤害
		if (GameController.Instance.IsGod) {    // 如果是上帝
			UIController.Instance.OnReStartGameClick();
		}
	}


	#region 设置蹲下状态
	/*	说明：
	 1. Crouch与Idle互斥
	 2. 单击下键并按住, Idle -> Crouch, 放开下键后恢复
	 3. 下楼梯时, 单击下键并按住, Idle -> Climb
	*/
	PKTStruct pktSPrev = new PKTStruct(0);
	PKTStruct pktSCurr = new PKTStruct(1);
	int cntSClick;
	private void OnUpdateSetCrouch() {

		if (Input.GetKeyDown(KeyCode.S) || Input.GetKeyDown(KeyCode.DownArrow)) {
			cntSClick = 1;
			pktSCurr = new PKTStruct(Time.realtimeSinceStartup, KeyCode.D);

			if (pktSCurr.key == pktSPrev.key) {
				float f = Mathf.Abs(pktSCurr.time - pktSPrev.time);
				if (f <= 0.3f) cntSClick = 2;
			}
		}

		if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) {
			if (!AllowCrouch) {
				SetPlayerState(PlayerState.Crouch, false);
				// SetPlayerState(PlayerState.MoveState, 0);       // MoveState = 0, IsIdle = true 都表示Idle
				// SetPlayerState(PlayerState.Idle, true);
				return;
			}
			SetPlayerState(PlayerState.Idle, false);
			SetPlayerState(PlayerState.MoveState, -1);
			SetPlayerState(PlayerState.Crouch, true);
		}

		if (Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.DownArrow)) {
			SetPlayerState(PlayerState.Crouch, false);
			SetPlayerState(PlayerState.MoveState, 0);       // MoveState = 0, IsIdle = true 都表示Idle
			SetPlayerState(PlayerState.Idle, true);
			// Debug.Log("UP");
		}



	}

	#endregion


	#region Player移动方法
	/*	说明:
	 1. 无操作情况下保持Idle状态, 速度 = 0
	 2. 单击并按住左右键, 向左右方向Walk, 速度1 * speed
	 3. 双击并按住左右键, 向左右方向Run, 速度2 * speed
	 4. 双击左右键并松开, 向左右方向Dash, 快速冲刺一段距离 速度 > 2 * speed
	 5. 左右移动过程中碰到Wall, 停止该方向的运动, 速度 = 0
	 6. 以上每种状态对应不同的帧动画
	 7. 方法在Update中执行
	*/

	PKTStruct pktADPrev = new PKTStruct(0);
	PKTStruct pktADCurr = new PKTStruct(1);
	int cntADClick;   // 0不动, 1步行, 2奔跑Or猛冲, 3撞墙
	private void OnUpdateMoveState() {

		if (ani.GetBool("IsCrouch")) {  // 如果蹲下, 只能缓慢行驶
			cntADClick = 1;
			return;
		}

		// 判断向左步行或奔跑
		if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow)) {
			cntADClick = 1;
			SetPlayerState(PlayerState.MoveState, 0);
			pktADCurr = new PKTStruct(Time.realtimeSinceStartup, KeyCode.A);

			if (pktADCurr.key == pktADPrev.key) {
				float f = Mathf.Abs(pktADCurr.time - pktADPrev.time);
				if (f <= 0.3f) cntADClick = 2;      // 连续两次按下
			}
		}
		// 判断向右步行或奔跑
		if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow)) {
			cntADClick = 1;
			SetPlayerState(PlayerState.MoveState, 0);   // Idle

			pktADCurr = new PKTStruct(Time.realtimeSinceStartup, KeyCode.D);
			if ((int)pktADCurr.key == (int)pktADPrev.key) {
				float f = Mathf.Abs(pktADCurr.time - pktADPrev.time);
				if (f <= 0.3f) cntADClick = 2;
			}
		}

		// 步行或奔跑, 单击并按住或双击并按住
		if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) ||
			Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)) {

			// Debug.Log(cntADClick);
			if (cntADClick == 1)
				SetPlayerState(PlayerState.MoveState, 1);       // 步行
			else if (cntADClick == 2)
				SetPlayerState(PlayerState.MoveState, 2);       // 奔跑
			else if (cntADClick == 3) {
				SetPlayerState(PlayerState.WallClinging, true);
				SetPlayerState(PlayerState.MoveState, -1);       // other
			}
		}

		// 恢复Idle状态
		if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.LeftArrow) ||
			Input.GetKeyUp(KeyCode.RightArrow) || Input.GetKeyUp(KeyCode.D)) {

			pktADPrev = pktADCurr;
			SetPlayerState(PlayerState.WallClinging, false);    // 退出贴墙

			// 是否猛冲?
			if (cntADClick == 2 && Mathf.Abs(Time.realtimeSinceStartup - pktADPrev.time) <= 0.3f) {    // 双击不按住
				if (AllowMove && AllowDash) {
					bool dir = Direction;
					// Debug.Log("dir:" + dir);
					ChangeMirrorPlayer(dir);
					StartCoroutine(DashDistance(dir));
				} else {    // 在冷却中, 不能Dash
					SetPlayerState(PlayerState.MoveState, 0);           // Idle
				}
			} else {
				SetPlayerState(PlayerState.MoveState, 0);           // Idle
				cntADClick = 0;
			}
		}
	}


	private bool waitDash;      // 不能连续猛冲, 需要等待
	/// <summary>
	/// 向一个方向猛冲一段距离
	/// </summary>
	/// <param name="isRight"></param>
	/// <returns></returns>
	private IEnumerator DashDistance(bool isRight) {
		SetPlayerState(PlayerState.MoveState, 3);
		waitDash = true;
		UIController.Instance.UseSkill(SkillUIType.SkillDash);
		int loop = 30;
		int dir = isRight ? 1 : -1;
		while (loop > 0) {
			yield return null;
			transform.position += Vector3.right * dir * Time.deltaTime * 8;
			loop--;
		}
		SetPlayerState(PlayerState.MoveState, 0);

		yield return new WaitForSeconds(1);     // 等待两秒后才可以再次使用猛冲

		UIController.Instance.ReleaseSkill(SkillUIType.SkillDash);
		yield return new WaitForSeconds(0.6f);     // 等待两秒后才可以再次使用猛冲
		waitDash = false;
	}

	/// <summary>
	/// 改变人物方向
	/// </summary>
	/// <param name="isRight"></param>
	private void ChangeMirrorPlayer(bool isRight) {
		Vector3 v = transform.localScale;
		v.x = isRight ? Mathf.Abs(v.x) : -Mathf.Abs(v.x);
		transform.localScale = v;
	}
	#endregion


	#region 设置进入离开动画事件

	/// <summary>
	/// 进入动画前事件
	/// </summary>
	/// <param name="state"></param>
	public void OnEnterAniEvent(PlayerState state) {
		isCompleted[state] = true;
		switch (state) {
			case PlayerState.Jump:
				rig.AddForce(Vector3.up * 360);
				// Debug.Log(Time.realtimeSinceStartup);
				UIController.Instance.UseSkill(SkillUIType.SkillJump);
				break;
			case PlayerState.Shoot:
				StartCoroutine(SetShootDirection());
				UIController.Instance.UseSkill(SkillUIType.SkillShoot);
				break;
			case PlayerState.Melee:
				UIController.Instance.UseSkill(SkillUIType.SkillMelee);
				break;

			default:
				break;
		}
	}


	/// <summary>
	/// 动画中间添加事件
	/// </summary>
	public void OnStayAniEvent(PlayerState state) {
		switch (state) {
			case PlayerState.Jump:
				// Debug.Log(Time.realtimeSinceStartup);
				UIController.Instance.ReleaseSkill(SkillUIType.SkillJump);
				Debug.Log("中间");
				break;
			case PlayerState.Melee:
				UIController.Instance.ReleaseSkill(SkillUIType.SkillMelee);
				break;

			case PlayerState.Shoot:
				UIController.Instance.ReleaseSkill(SkillUIType.SkillShoot);
				break;

			default:
				break;
		}
	}


	/// <summary>
	/// 退出动画后事件，
	/// 一般对于非循环动画事件有效
	/// </summary>
	/// <param name="state"></param>
	public void OnExitAniEvent(PlayerState state) {
		isCompleted[state] = false;
		// Debug.Log("Exit" + state);
		switch (state) {
			case PlayerState.Jump:
				Debug.Log("后面");
				// Debug.Log(Time.realtimeSinceStartup);
				break;
			case PlayerState.Melee:
				// UIController.Instance.ReleaseSkill(SkillUIType.SkillMelee);

				break;

			default:
				break;
		}
	}

	#endregion


	#region 射击动画前事件相关方法

	/// <summary>
	/// 射击前确定射击方向
	/// </summary>
	/// <returns></returns>
	private IEnumerator SetShootDirection() {
		ani.enabled = false;
		GetComponent<SpriteRenderer>().sprite = shootDirs[(int)Dir % 5];
		if (!GameController.Instance.IsPause) {   // 没有暂停{
			Instantiate(bltPrefab, transform);
			if (!GameController.Instance.IsGod)     // 非上帝模式才消耗子弹数量
				CurrentMp = Mathf.Max(0, CurrentMp - 1);
			UIController.Instance.SetHPAndMP(this);
		}

		yield return new WaitForSeconds(0.3f);
		ani.enabled = true;
	}

	/// <summary>
	/// 获取射击方向
	/// </summary>
	private void OnUpdateGetShootDirection() {
		if (isCompleted[PlayerState.Shoot]) return; // 射击动作还没有完成

		float y = Input.GetAxis("Vertical");
		float x = Input.GetAxis("Horizontal");
		if (y != 0) {
			if (x != 0) {   // 斜上或斜下
				if (x > 0) {
					dir = y > 0 ? ShootDirection.RightUp : ShootDirection.RightDown;
				} else {
					dir = y > 0 ? ShootDirection.LeftUp : ShootDirection.LeftDown;
				}
			} else {        // 上下方向
				dir = y > 0 ? ShootDirection.Up : ShootDirection.Down;
			}
		} else {    // 没有上下偏移
			if (x != 0) dir = x > 0 ? ShootDirection.Right : ShootDirection.Left;
		}
	}
	#endregion


	#region 设置显示动画
	public void SetPlayerState(PlayerState state) {
		this.state = state;
		ani.SetTrigger("Is" + state.ToString());
	}
	public void SetPlayerState(PlayerState state, bool b) {
		this.state = state;
		ani.SetBool("Is" + state.ToString(), b);
	}
	public void SetPlayerState(PlayerState state, int i) {
		this.state = state;
		ani.SetInteger(state.ToString(), i);
	}
	public void SetPlayerState(PlayerState state, float f) {
		this.state = state;
		ani.SetFloat(state.ToString(), f);
	}
	#endregion

}